/**
 * 
 * @param size
 * @returns ChessBoardModel
 */
function ChessBoardModel(size) {
	this.size = size;
	this.data = this.createEmptyBoard();
}

ChessBoardModel.prototype.createEmptyBoard = function() {
	var data = [];

	for ( var row = 0; row < this.size; row++) {
		for ( var col = 0; col < this.size; col++) {
			data.push(0);
		}
	}

	return data;
};

ChessBoardModel.prototype.placeAt = function(row, col) {
	var couldPlace = this.canPlaceAt(row, col);

	if (couldPlace) {
		this.setValueAt(row, col, -1);

		for ( var i = 1; i < this.size; i++) {
			this.setValueAt(row + i, col, i);
			this.setValueAt(row - i, col, i);

			this.setValueAt(row, col + i, i);
			this.setValueAt(row, col - i, i);

			this.setValueAt(row + i, col + i, i);
			this.setValueAt(row - i, col - i, i);

			this.setValueAt(row + i, col - i, i);
			this.setValueAt(row - i, col + i, i);
		}
	}

	return couldPlace;
};

ChessBoardModel.prototype.canPlaceAt = function(row, col) {
	return this.getValueAt(row, col) == 0;
};

ChessBoardModel.prototype.getValueAt = function(row, col) {
	return this.data[this.getIndex(row, col)];
};

ChessBoardModel.prototype.setValueAt = function(row, col, value) {
	if (this.isInBounds(row) && this.isInBounds(col)) {
		var index = this.getIndex(row, col);
		this.data[index] = value;
	}
};

ChessBoardModel.prototype.isInBounds = function(x) {
	return x >= 0 && x < this.size;
};

ChessBoardModel.prototype.getIndex = function(row, col) {
	return row * this.size + col;
};

ChessBoardModel.prototype.isSolved = function() {
	return this.evaluateState().solved;
};

ChessBoardModel.prototype.isStale = function() {
	var state = this.evaluateState();
	return !state.inProgress && !state.solved;
};

ChessBoardModel.prototype.evaluateState = function() {
	var inProgress = false;

	var countQueens = 0;
	for ( var i = 0; i < this.data.length; i++) {
		if (this.data[i] == 0) {
			inProgress = true;
			break;
		} else if (this.data[i] == -1) {
			countQueens++;
		}
	}

	var solved = (countQueens === this.size);
	return {
		solved : solved,
		inProgress : inProgress
	};
};

/**
 * 
 * @param size
 * @param view
 * @returns NQueensController
 */
function NQueensController(size, view) {
	this.size = size;
	this.view = view;
	this.model = new ChessBoardModel(size);

	this.view.init(this);
}

NQueensController.prototype.show = function() {
	this.repaint();
};

NQueensController.prototype.repaint = function() {
	this.view.refresh(this.model.data);
};

NQueensController.prototype.onPlace = function(row, col) {
	var result = this.model.placeAt(row, col);
	this.repaint();

	if (this.model.isSolved()) {
		var puzzleId = this.size + "queens";
		new AEnigmatesStorage(puzzleId).solved();
		this.view.onSolved();
	}

	if (this.model.isStale()) {
		this.view.onStale();
	}

	return result;
};

NQueensController.prototype.onReset = function() {
	this.model = new ChessBoardModel(this.size);
	this.repaint();
};